From 82f5d7e034952c4c035682c4ba8ed74158234e14 Mon Sep 17 00:00:00 2001 From: "Ian.Campbell@xensource.com" Date: Fri, 13 Jan 2006 14:59:40 +0000 Subject: [PATCH] Debug keyhandlers for triggering an NMI and examine current NMI state. Add 'N' keyhandler to dump the current per CPU NMI counts and the current NMI mask/pending status. Add 'n' keyhandler to trigger an NMI by sending an IPI. For some reason the destination shorthand for self is not valid when used with the NMI delivery mode so we send the IPI to our own APIC ID explicitly. Signed-off-by: Ian Campbell --- xen/arch/x86/nmi.c | 25 +++++++++++++++++++++++++ xen/common/keyhandler.c | 22 ++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/xen/arch/x86/nmi.c b/xen/arch/x86/nmi.c index d2ccd4e7e4..f8c34a1c27 100644 --- a/xen/arch/x86/nmi.c +++ b/xen/arch/x86/nmi.c @@ -23,12 +23,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include unsigned int nmi_watchdog = NMI_NONE; static spinlock_t watchdog_lock = SPIN_LOCK_UNLOCKED; @@ -448,3 +450,26 @@ void nmi_watchdog_tick(struct cpu_user_regs * regs) write_watchdog_counter(NULL); } } + +/* + * For some reason the destination shorthand for self is not valid + * when used with the NMI delivery mode. This is documented in Tables + * 8-3 and 8-4 in IA32 Reference Manual Volume 3. We send the IPI to + * our own APIC ID explicitly which is valid. + */ +static void do_nmi_trigger(unsigned char key) { + u32 id = apic_read(APIC_ID); + + printk("triggering NMI on APIC ID %x\n", id); + + apic_wait_icr_idle(); + apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(id)); + apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_INT_ASSERT); +} + +static __init int register_nmi_trigger(void) +{ + register_keyhandler('n', do_nmi_trigger, "trigger an NMI"); + return 0; +} +__initcall(register_nmi_trigger); diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c index b239391462..5fc1e6b04c 100644 --- a/xen/common/keyhandler.c +++ b/xen/common/keyhandler.c @@ -185,6 +185,27 @@ void do_debug_key(unsigned char key, struct cpu_user_regs *regs) bit. */ } +void do_nmi_stats(unsigned char key) +{ + int i; + struct domain *d; + struct vcpu *v; + printk("CPU\tNMI\n"); + for_each_cpu(i) + printk("%3d\t%3d\n", i, nmi_count(i)); + + if ((d = dom0) == NULL) + return; + if ((v = d->vcpu[0]) == NULL) + return; + if (v->vcpu_flags & (VCPUF_nmi_pending|VCPUF_nmi_masked)) + printk("dom0 vpu0: NMI %s%s\n", + v->vcpu_flags & VCPUF_nmi_pending ? "pending " : "", + v->vcpu_flags & VCPUF_nmi_masked ? "masked " : ""); + else + printk("dom0 vcpu0: NMI neither pending nor masked\n"); +} + #ifndef NDEBUG void debugtrace_key(unsigned char key) { @@ -213,6 +234,7 @@ void initialize_keytable(void) 'r', dump_runq, "dump run queues"); register_irq_keyhandler( 'R', halt_machine, "reboot machine"); + register_keyhandler('N', do_nmi_stats, "NMI statistics"); #ifndef NDEBUG register_keyhandler( -- 2.30.2